/*
 * GameController.hpp
 *
 *  Created on: 27/dic/2012
 *      Author: stefano.pesenti
 */

#ifndef GAMECONTROLLER_HPP_
#define GAMECONTROLLER_HPP_

#include <cassert>

class GameController {

private:
	GameModel* model;
	GameView* view;

	int lastXPosition;
	int lastYPosition;
	void loadMap();

public:
	GameController() :
			model(0), view(0), lastXPosition(-1), lastYPosition(-1) {
	}

	int initialize(GameModel* const model, GameView* const view);
	int update();
};

void GameController::loadMap() {
	int mapWidth = this->model->getMapWidth();
	int mapHeight = this->model->getMapheight();
	int sectionDimension = this->model->getSectionDimension();
	glm::vec3 position = this->view->getCamera().position();
	int xPosition = (int) (position.x / sectionDimension) % mapWidth;
	int yPosition = (int) (position.y / sectionDimension) % mapHeight;
	if (this->lastXPosition == xPosition && this->lastYPosition == yPosition)
		return;
	this->lastXPosition = xPosition;
	this->lastYPosition = yPosition;
	int visibleRange = this->model->getVisibleRange();

	for (int x = xPosition - visibleRange; x <= xPosition + visibleRange; x++) {
		for (int y = yPosition - visibleRange; y <= yPosition + visibleRange; y++) {
			if (x < 0 || y < 0 || x >= mapWidth || y >= mapHeight || this->model->isSectionLoaded(x, y))
				continue;

			float* sectionValues = new float[sectionDimension * sectionDimension];

			std::string path = "data/map/" + to_str(x) + "_" + to_str(y);
			jsl::Node* map = zen::sys::Resources::load(path);

			if (map) {
				jsl::Node* area = map->at("heightMap");
				size_t areaSize = area->size();
				for (unsigned int i = 0; i < areaSize; i++) {
					jsl::Node* cell = area->at(i);
					for (int j = 0; j < sectionDimension; j++) {
						float point = cell->at(j)->asFloat();
						assert(point < 20);
						sectionValues[i * areaSize + j] = point;
					}
				}

				zen::video::Section section;
				section.initialize(sectionValues);

				this->model->loadSection(x, y, section);
				std::cout << "loaded section: " << x << " " << y << std::endl;
			}
		}
	}
}

int GameController::initialize(GameModel* const model, GameView* const view) {
	this->model = model;
	this->view = view;
	this->model->initialize(view);
	this->view->initialize(model);

	this->loadMap();

	return 0;
}

int GameController::update() {

	if (zen::sys::Window::keyHit(zen::sys::kEscape)) {
		return zen::sys::FRAMER_EXIT;
	}

	if (zen::sys::Window::keyDown(zen::sys::kW)) {
		view->getCamera().moveY(0.2f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kS)) {
		view->getCamera().moveY(-0.1f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kA)) {
		view->getCamera().moveX(-0.1f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kD)) {
		view->getCamera().moveX(0.1f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kPageUp)) {
		view->getCamera().moveZ(0.1f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kPageDown)) {
		view->getCamera().moveZ(-0.1f);
		this->loadMap();
	}
	if (zen::sys::Window::keyDown(zen::sys::kQ))
		view->getCamera().turnZ((float)_PI * 0.01f);
	if (zen::sys::Window::keyDown(zen::sys::kE))
		view->getCamera().turnZ(-(float)_PI * 0.01f);
	if (zen::sys::Window::keyDown(zen::sys::kHome))
		view->getCamera().turnX((float)_PI * 0.01f);
	if (zen::sys::Window::keyDown(zen::sys::kEnd))
		view->getCamera().turnX(-(float)_PI * 0.01f);

	/// -------------------------------------------------------------------------------------------
	return zen::sys::FRAMER_CONTINUE;
}

#endif /* GAMECONTROLLER_HPP_ */
